using System;
using System.Drawing;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Modeling.Diagrams;

namespace Microsoft.Modeling.StoryboardDesigner
{
    internal static class MultiLineFieldHelper
    {
        #region Field size calcs
        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        internal static extern IntPtr GetDesktopWindow();

        /// <summary>
        /// Returns the size required for the field to display
        /// the text for the specified shape element with a 
        /// fixed width.
        /// </summary>
        /// <param name="pel"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public static SizeD GetRequiredSizeForFixedWidth(ShapeElement pel, TextField field)
        {
            // Parameter checks
            if(pel == null)
            {
                throw new ArgumentNullException("pel");
            }

            if(field == null)
            {
                throw new ArgumentNullException("field");
            }

            SizeD maxSize = field.GetBounds(pel).Size;
            maxSize.Height = 0;

            SizeD reqSize = MeasureDisplayText(
                field.GetDisplayText(pel),
                field.GetFont(pel),
                field.GetStringFormat(pel),
                maxSize);

            return reqSize;
        }

        /// <summary>
        /// Returns the size required for the field to display
        /// the text for the specified shape element with a 
        /// fixed width.
        /// </summary>
        /// <param name="pel"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public static SizeD GetRequiredSizeForFixedWidth(ShapeElement pel, TextField field, double width)
        {
            // Parameter checks
            if(pel == null)
            {
                throw new ArgumentNullException("pel");
            }

            if(field == null)
            {
                throw new ArgumentNullException("field");
            }

            SizeD maxSize = new SizeD(width, 0);

            SizeD reqSize = MeasureDisplayText(
                field.GetDisplayText(pel),
                field.GetFont(pel),
                field.GetStringFormat(pel),
                maxSize);

            return reqSize;
        }

        /// <summary>
        /// Wrapper for the DLL call
        /// </summary>
        /// <param name="displayText"></param>
        /// <param name="font"></param>
        /// <param name="format"></param>
        /// <param name="maximumSize"></param>
        /// <returns></returns>
        private static SizeD MeasureDisplayText(string displayText, Font font, StringFormat format, SizeD maximumSize)
        {
            int charsFitted;
            int linesFilled;

            using(Graphics graphics1 = Graphics.FromHwnd(GetDesktopWindow()))
            {
                SizeF ef1 = graphics1.MeasureString(
                        displayText, 
                        font, 
                        SizeD.ToSizeF(maximumSize), 
                        format, 
                        out charsFitted, 
                        out linesFilled);

                return new SizeD((double)ef1.Width, (double)ef1.Height);
            }
        }
        #endregion

        #region MultiLineField creation

        public static TextField GetMultiLineTextField(
            NodeShape parentShape,
            string name, bool anchorToParent)
        {
            TextField field1 = new DemoTextField(name);

            field1.FillBackground = false;
            field1.DrawBorder = false;
            field1.DefaultPenId = DiagramPens.ShapeTitleOutline;
            field1.DefaultBackgroundBrushId = DiagramBrushes.ShapeTitleBackground;
            field1.DefaultFontId = DiagramFonts.CommentText;
            field1.DefaultStringFormat = CreateDefaultStringFormat();
            field1.DefaultStringFormat.Alignment = StringAlignment.Near;
            field1.DefaultStringFormat.LineAlignment = StringAlignment.Near;
            field1.DefaultFocusable = true;
            field1.DefaultMultipleLine = true;
            field1.DefaultCommitOnEscape = true;
            field1.DefaultAccessibleDescription = "Accessible Desc";

            if(anchorToParent)
            {
                Anchor(field1);
            }

            return field1;
        }

        internal static void Anchor(ShapeField shapeField)
        {
            TextField field = (TextField)shapeField;
            double num1 = 0.01;
            field.AnchoringBehavior.SetLeftAnchor(AnchoringBehavior.Edge.Left, num1);
            field.AnchoringBehavior.SetRightAnchor(AnchoringBehavior.Edge.Right, num1);
            field.AnchoringBehavior.SetTopAnchor(AnchoringBehavior.Edge.Top, num1);
            field.AnchoringBehavior.SetBottomAnchor(AnchoringBehavior.Edge.Bottom, num1);
            field.AnchoringBehavior.MinimumHeightInLines = 1;
        }

        static internal StringFormat CreateDefaultStringFormat()
        {
            StringFormat format = new StringFormat(StringFormatFlags.NoClip);
            format.Trimming = StringTrimming.EllipsisWord;
            format.Alignment = StringAlignment.Center;
            format.LineAlignment = StringAlignment.Center;

            return format;
        }

        #endregion
    }
}